package com.chimm.redpacket.demo_redis.controller;

import com.chimm.redpacket.bean.RedPacket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 抢红包设计方式一
 *
 * @author Chimm Huang
 */
@RestController
@RequestMapping("/demo01")
public class Demo01Controller {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Controller.class);

    @Autowired
    private RedissonClient redissonClient;

    private static final String RED_PACKET_KEY = "red_packet_demo01";
    private static final String RED_PACKET_LOCK_KEY = "red_packet_demo01_lock";

    @RequestMapping("/add")
    public String addRedPacket(BigDecimal money, Integer num) {
        // 让开，我要发红包啦
        RedPacket redPacket = new RedPacket(money, num);
        logger.info("================ 红包来啦，金额：{} 元，数量：{} 个 ================", money, num);

        // 生成红包id
        String id = UUID.randomUUID().toString().replace("-", "");
        redissonClient.getMap(RED_PACKET_KEY).put(id, redPacket);
        return "红包已发送，id为：" + id;
    }

    @RequestMapping("/get")
    public String getRedPacket(String id, String userId) {
        // 上锁
        RLock lock = redissonClient.getLock(RED_PACKET_LOCK_KEY);
        BigDecimal money = BigDecimal.ONE;
        boolean hasRedPacket = false;

        try {
            if (lock.tryLock(10, 10, TimeUnit.SECONDS)) {
                // 1.从缓存中读取红包
                RedPacket redPacket = (RedPacket) redissonClient.getMap(RED_PACKET_KEY).get(id);

                // 2. 判断是否还有红包
                if (redPacket != null && redPacket.getRemainNum() > 0) {
                    hasRedPacket = true;
                    // 3. 获取随机金额
                    money = this.getRandomMoney(redPacket);
                    logger.info("================ 用户：{} 抢到了：{} 元 ================", userId, money);
                    // 4. 修改redis
                    if (redPacket.getRemainNum() == 0) {
                        // 删除redis中的红包
                        redissonClient.getMap(RED_PACKET_KEY).remove(id);
                    } else {
                        redissonClient.getMap(RED_PACKET_KEY).put(id, redPacket);
                    }
                }
            }
        } catch (InterruptedException e) {
            logger.error("加锁出现异常:{}", e.getMessage(), e);
        } finally {
            // 释放锁
            lock.unlock();
        }
        return hasRedPacket ? "抢到红包，金额为：" + money : "手慢了";
    }

    /**
     * 获取红包金额
     */
    public BigDecimal getRandomMoney(RedPacket redPacket) {
        // 剩余的红包数量
        Integer remainingNum = redPacket.getRemainNum();
        // 剩余的金额
        BigDecimal remainingAmount = redPacket.getRemainAmount();
        if (remainingNum == 1) {
            redPacket.setRemainNum(--remainingNum);
            redPacket.setRemainAmount(BigDecimal.ZERO);
            // 返回剩余金额
            return remainingAmount;
        }
        Random r = new Random();
        //最小金额
        BigDecimal min = BigDecimal.valueOf(0.01);
        //最大金额（开区间）
        BigDecimal max = remainingAmount.divide(new BigDecimal(remainingNum), 2, RoundingMode.DOWN).multiply(BigDecimal.valueOf(2L));

        //获取随机金额,不超过最大值max
        BigDecimal money = BigDecimal.valueOf(r.nextDouble()).multiply(max);
        // 如果随机金额=0，则取最小的值
        money = money.compareTo(min) <= 0 ? min : money;
        //向下取整后取小数点后2位
        money = money.setScale(2, RoundingMode.DOWN);

        //设置剩余金额
        remainingAmount = remainingAmount.subtract(money);
        redPacket.setRemainAmount(remainingAmount);
        //设置剩余红包个数
        redPacket.setRemainNum(--remainingNum);
        return money;
    }
}
